*/* $Header: std_ops.hs,v 2.2 01/10/02 10:30:42 przybyls Exp $ */
  save          ;Save command-line options ... macros may RESTORE.
  nolist

* std_ops.hs .... an include file
* ===============================

************************************************************************
*                                                                      *
*                  Copyright Hewlett-Packard Co. 1991                  *
*                                                                      *
************************************************************************

************************************************************************
*                                                                      *
*  File std_ops.hs defines standard macros and conditional assembly    *
*  control flags which are used throughout the CDH-Core firmware.      *
*  The assembler directive "INCLUDE std_ops.hs" must appear at the     *
*  beginning of EVERY assembly source file (but NOT include files).    *
*                                                                      *
*  NOTE:  Macros and flags whose names begin with the prefix "??"      *
*  ----   are normally omitted from the assembler symbol table and     *
*         relocatable object files.  (See as68k option -fg.)           *
*                                                                      *
************************************************************************

                LLEN  127       ;Max for Laserjet compressed ("lp -oc").
                PLEN  65        ;60..61 source lines plus as68k headers.


DEBUG           set   1         ;DEBUG flag controls the generation of
  ??Debug:      set   DEBUG     ;extra code to assist emulation/trace.


??ListI         set             0               ;By default do NOT
                                                ;list include-files.


LIST_I          MACRO                           ;Use "LIST_I" to
  ??ListI:        set           1               ;enable include-file
                ENDM                            ;listings.


NOLIST_I        MACRO                           ;Use "NOLIST_I" to
  ??ListI:        set           0               ;disable include-file
                ENDM                            ;listings.


??PAGE          MACRO                           ;Use "??PAGE" instead
                  ifne          ??ListI         ;of "page" in Ifiles
                    page                        ;to avoid a page-eject
                  endc                          ;after every "INCLUDE"
                ENDM                            ;directive.


  ??PAGE
* std_ops.hs .... MACROs for MACROs
* =================================

************************************************************************
*                                                                      *
*  The "??FAIL_" macros are used by other macros to perform assembly-  *
*  time validity tests on user-supplied macro arguments (parameters).  *
*  Successful tests do not affect assembly...but the detection of an   *
*  UNEXPECTED, ILLEGAL, or MISSING argument forces an assembly error.  *
*                                                                      *
*    ??FAIL_p  <args>   (Fail if unexpected parameter(s) exist.)       *
*    ----------------    ^^^^               ^^^^^^^^^                  *
*      This macro is used to check for unexpected macro parameters;    *
*      it causes the assembler to FAIL unless all of the arguments     *
*      specified by <args> are null.  For example, "??FAIL_p  <\0>"    *
*      causes an assembly error if any data-size qualifier (arg0)      *
*      is specified by the user;  the statement "??FAIL_p <\0\4\5>"    *
*      generates an error unless arg0, arg4, and arg5 are ALL null.    *
*      Any number of elements may be concatenated in <args>;  but,     *
*      multiple elements must be specified using Motorola backslash    *
*      notation, and commas must NOT be used to separate arguments.    *
*                                                                      *
*    ??FAIL_np  <arg>,{list}   (Fail if no legal parameter exists.)    *
*    -----------------------    ^^^^    ^^       ^^^^^^^^^             *
*      This macro is used to test the validity of macro parameters;    *
*      it causes the assembler to FAIL unless parameter <arg> is a     *
*      member of the "valid parameter set".  {list} consists of one    *
*      or more (up to 8) comma-separated elements listing all legal    *
*      values of <arg>.  For example, "??FAIL_np  <\2>,A7,a7,SP,sp"    *
*      will fail unless arg2 is a member of the set {A7,a7,SP,sp}.     *
*      Besides "exact match" elements, the valid argument list may     *
*      include the following "special symbols":                        *
*                                                                      *
*      The NULL SYMBOL "< >" (...with exactly ONE space!) specifies    *
*      that <arg> may be null;  this is useful for testing optional    *
*      parameters.  For example, "??FAIL_np  <\0>,B,b,W,w,L,l,< >"     *
*      is frequently used to test optional size-qualifiers, (arg0):    *
*      "Arg0, IF SPECIFIED, must belong to the set {B,b,W,w,L,l}".     *
*                                                                      *
*      The WILD-CARD SYMBOL "<*>" specifies that ANY non-null <arg>    *
*      is considered valid;  this permits simple existance tests in    *
*      cases where the legal parameter values cannot be enumerated.    *
*      Thus, "??FAIL_np  <\1>,<*>" simply verifies that arg1 exists.   *
*      Note that the "<*>" symbol must be the first element of the     *
*      valid argument list if it is to be recognized as a wild-card;   *
*      consequently, the following statements are NOT equivalent:      *
*      (a).  ??FAIL_np  <\1>,<*>,< >  ....this test can NEVER fail!    *
*      (b).  ??FAIL_np  <\1>,< >,<*>  ....arg1 (if any) must be "*".   *
*                                                                      *
*  The "FAIL_" macros use the as68k directive "ifne ==\1" to test for  *
*  existance.  Since this method handles semicolon-delimited comments  *
*  properly, the "FAIL_" macros are immune to the "comment-confusion"  *
*  problems encountered with direct null-comparisons (ifnc  '\1','')   *
*  and NARG-counts.  Note that the "==" operator does NOT distinguish  *
*  between nulls (<>) and blanks (< >) -- this might conceivably be a  *
*  problem for macros that must process blank arguments (strings?).    *
*                                                                      *
************************************************************************

  ??PAGE
* std_ops.hs .... MACROs for MACROs
* =================================


??FAIL_p        MACRO                           ;If arg1 exists, FAIL.
                  ifne          ==\1
                    opt mex               ! No argument permitted here.
                      fail (499)          ! Unexpected MACRO Arg: "\1"
                    restore
                  endc
                ENDM


??FAIL_np       MACRO
                  ifne          ==\1            ;If arg1 exists then
                    ifnc        '\2','*'        ;  if   arg2=wild ..OK!
                    ifnc        '\1','\2'       ;  elif arg1=arg2 ..OK!
                    ifnc        '\1','\3'       ;  elif arg1=arg3 ..OK!
                    ifnc        '\1','\4'       ;  .     .    .     .
                    ifnc        '\1','\5'       ;  .     .    .     .
                    ifnc        '\1','\6'       ;  .     .    .     .
                    ifnc        '\1','\7'       ;  elif arg1=argN ..OK!
                    ifnc        '\1','\8'       ;  else Bad_Arg ..FAIL!
                    ifnc        '\1','\9'
                      opt mex             ! Expected: \2 \3 \4 \5 \6 \7 \8 \9
                        fail (499)        ! Illegal MACRO Argument: "\1"
                      restore
                    endc
                    endc
                    endc
                    endc
                    endc
                    endc
                    endc
                    endc
                    endc
                  elsec                         ;else (arg1 is null)
                    ifnc        ' ','\2'        ;  if   arg2=< > ..OK!
                    ifnc        ' ','\3'        ;  elif arg3=< > ..OK!
                    ifnc        ' ','\4'        ;   .    .    .    .
                    ifnc        ' ','\5'        ;   .    .    .    .
                    ifnc        ' ','\6'        ;   .    .    .    .
                    ifnc        ' ','\7'        ;  elif argN=< > ..OK!
                    ifnc        ' ','\8'        ;  else No_Arg ..FAIL!
                    ifnc        ' ','\9'
                      opt mex             ! Expected: \2 \3 \4 \5 \6 \7 \8 \9
                        fail (499)        ! Missing MACRO Argument!
                      restore
                    endc
                    endc
                    endc
                    endc
                    endc
                    endc                        ;Could easily add more
                    endc                        ;levels ...if's can be
                    endc                        ;nested up to 64-deep!
                  endc
                ENDM

  ??PAGE
* std_ops.hs .... PUSH and POP Operations
* =======================================

************************************************************************
*                                                                      *
*  PUSH and POP may specify any <ea> which is a legal operand for the  *
*  68xxx  "MOVE  <ea>,-(SP)"  or  "MOVE  (SP)+,<ea>"  instructions.    *
*  The optional type qualifier, if specified, must be ".B", ".W", or   *
*  ".L";  if no qualifier is specified, the operations default to      *
*  type WORD.                                                          *
*                                                                      *
*    PUSH.x  <ea>         Push <ea> onto stack.  (x = B/W/L/none)      *
*                                                                      *
*    POP.x   <ea>         Pop <ea> from stack.   (x = B/W/L/none)      *
*                                                                      *
************************************************************************


PUSH            MACRO           source_ea
                  ??FAIL_np     <\0>,B,b,W,w,L,l,< > ;Qual = B/W/L/none,
                  ??FAIL_np     <\1>,<*>             ;arg1 must exist,
                  ??FAIL_p      <\4\5\6\7\8\9>       ;arg4... must not.
                  ifeq          ==\2\3               ;If only arg1,
                    move.\0     \1,-(sp)             ;  (simple_addr)
                  elsec                              ;else
                    ifeq        ==\3                 ;  if arg1,arg2
                      move.\0   \1,\2,-(sp)          ;    (disp,Reg)
                    elsec                            ;  else   ^
                      move.\0   \1,\2,\3,-(sp)       ;    (disp,Rn,Xn)
                    endc                             ;  endif  ^  ^
                  endc                               ;endif
                ENDM



POP             MACRO           destination_ea
                  ??FAIL_np     <\0>,B,b,W,w,L,l,< > ;Qual = B/W/L/none,
                  ??FAIL_np     <\1>,<*>             ;arg1 must exist,
                  ??FAIL_p      <\4\5\6\7\8\9>       ;arg4... must not.
                  ifeq          ==\2\3               ;If only arg1,
                    move.\0     (sp)+,\1             ;  (simple_addr)
                  elsec                              ;else
                    ifeq        ==\3                 ;  if arg1,arg2
                      move.\0   (sp)+,\1,\2          ;    (disp,Reg)
                    elsec                            ;  else   ^
                      move.\0   (sp)+,\1,\2,\3       ;    (disp,Rn,Xn)
                    endc                             ;  endif  ^  ^
                  endc                               ;endif
                ENDM


  ??PAGE
* std_ops.hs .... PUSHM and POPM Operations
* =========================================

************************************************************************
*                                                                      *
*  PUSHM and POPM may specify any <reg_list> which is a legal operand  *
*  for the 68xxx "MOVEM <reg_list>,-(SP)" or "MOVEM (SP)+,<reg_list>"  *
*  instructions.  The optional type qualifier, if specified, must be   *
*  either ".W" or ".L";  if no qualifier is specified, the operations  *
*  default to type WORD.                                               *
*                                                                      *
*    PUSHM.x <reg_list>    Push <reg_list> onto stack. (x = W/L/none)  *
*                                                                      *
*    POPM.x  <reg_list>    Pop <reg_list> from stack.  (x = W/L/none)  *
*                                                                      *
*                                                                      *
*  NOTE:  POPM.W sign-extends both data-register and address-register  *
*  ====   operands to 32-bit long words.                               *
*                                                                      *
************************************************************************


PUSHM           MACRO           reg_list
                  ??FAIL_np     <\0>,W,w,L,l,< >     ;Qual = W/L/none,
                  ??FAIL_np     <\1>,<*>             ;arg1 must exist,
                  ??FAIL_p      <\2\3\4\5\6\7\8\9>   ;no other args.
                  movem.\0      \1,-(sp)
                ENDM



POPM            MACRO           reg_list
                  ??FAIL_np     <\0>,W,w,L,l,< >     ;Qual = W/L/none,
                  ??FAIL_np     <\1>,<*>             ;arg1 must exist,
                  ??FAIL_p      <\2\3\4\5\6\7\8\9>   ;no other args.
                  movem.\0      (sp)+,\1
                ENDM


  ??PAGE
* std_ops.hs .... BEGIN_Module / END_Module
* =========================================

************************************************************************
*                                                                      *
*  BEGIN_Module  <module_name>                                         *
*  ---------------------------                                         *
*  If a module_name was specified then                                 *
*    Encode module_name in ??Mname (32-bit numeric)                    *
*    Declare module_name via IDNT (symbolic)                           *
*  Else                                                                *
*    Set ??Mname to $FFFFFFFF (can NEVER match ??Iname)                *
*  End                                                                 *
*                                                                      *
*                                                                      *
*  END_Module  <module_name>                                           *
*  -------------------------                                           *
*  Currently just a "hook" for future use.                             *
*                                                                      *
*                                                                      *
*  The variable ??Mname is initialized to $FFFFFFFF (undefined) so     *
*  that no assembly errors will occur when processing a source file    *
*  which omits the BEGIN_Module macro while INCLUDE-ing files which    *
*  contain the BEGIN_Include/END_Include macros.                       *
*                                                                      *
************************************************************************


??Mname         set             $FFFFFFFF       ;??Mname := undefined.


BEGIN_Module    MACRO           module_name     ;Four characters max.
                ??FAIL_p        <\0\2\3\4\5\6>  ;Arg1 only (optional).
  ??Mbegun:       equ           1               ;Can only BEGIN once!
                  ifne          ==\1            ;If module name given
  ??Mname:          set         '\1'            ;  Mname:= 'arg1' (num)
  \1:               idnt                        ;  IDNT := "arg1" (sym)
                  elsec                         ;else
  ??Mname:          set         $FFFFFFFF       ;  Mname:= none ($FF..)
                  endc                          ;endif
                ENDM



END_Module      MACRO           module_name     ;Four characters max.
                ??FAIL_p        <\0\2\3\4\5\6>  ;Arg1 only (optional).
  ??Mdone:       equ            ??Mbegun        ;END only after BEGIN!
                PLEN            60              ;Workaround sym-tbl bug.
                ENDM


  ??PAGE
* std_ops.hs .... Code/Data SECTION Management
* ============================================


BEGIN_Data      MACRO           section_name
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify sect name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
                  opt now                       ;Suppress warning for
                    section     \1              ;short/long mismatch,
                  restore                       ;declare section name.
  ??DataStart:    set           *               ;Tag first byte of data.
                ENDM



END_Data        MACRO           section_name
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify sect name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
  DATA_BYTES:     set           *-??DataStart   ;Data byte-count.
                  offset        0               ;Not in any section.
                ENDM



BEGIN_Code      MACRO           section_name
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify sect name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
                  opt now                       ;Suppress warning for
                    section     \1              ;short/long mismatch,
                  restore                       ;declare section name.
                  ifne          ??Debug         ;If ??Debug=ON, insert
                    dc.l        0               ;spacer to avoid trace-
                  endc                          ;trig from prev module.
  ??CodeStart:    set           *               ;Tag first byte of data.
  ??ProcCount:    set           0               ;Zero procedure counter.
                ENDM



END_Code        MACRO           section_name
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify sect name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
  CODE_BYTES:     set           *-??CodeStart   ;Code byte-count.
                  offset        0               ;Not in any section.
                ENDM


  ??PAGE
* std_ops.hs .... Procedure Entry/Exit Accounting
* ===============================================


BEGIN_Proc      MACRO           procedure_name  ;Any legal identifier.
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify proc name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
                  ifne          ??Debug         ;If (debug_enabled) AND
                    ifne        ??ProcCount     ;(not_module's_1st_proc)
                      dc.l      0               ;insert spacer to avoid
                    endc                        ;triggering emulator on
                  endc                          ;unused opcode prefetch.
                  align         2               ;Force word-alignment.
  \1_begin:       equ           *               ;Lbl= <proc_name>_begin.
  ??ProcCount:    set           1+??ProcCount   ;Bump procedure counter.
                ENDM



ENTER_Proc      MACRO           procedure_name  ;Any legal identifier.
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify proc name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
                ENDM                            ;Hook for future needs.



EXIT_Proc       MACRO           procedure_name  ;Any legal identifier.
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify proc name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
                ENDM                            ;Hook for future needs.



END_Proc        MACRO           procedure_name  ;Any legal identifier.
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;must specify proc name,
                ??FAIL_p        <\2\3\4\5>      ;no other arguments.
  \1_BYTES:       equ           *-\1_begin      ;Put byte-count in XREF.
  \1_end:         equ           *-1             ;Label <proc_name>_end.
                ENDM


  ??PAGE
* std_ops.hs .... BEGIN_Ifile / END_Ifile
* =======================================


??Ibegun        set             1               ;In Ifile...(std_ops).
??Iname         set             $00000000       ;Iname := undefined.


BEGIN_Ifile     MACRO           ifile_name      ;Four characters max.
                ??FAIL_p        <\0\2\3\4\5>    ;Arg1 only...optional.
                  ifne          ??Ibegun        ;Check: Nested BEGINs?
                    fail  (499)               ! Nested BEGIN_Ifile's.
                  endc                          ;FAIL if nested BEGINs.
  ??Ibegun:       set           1               ;Record I-file entry.
  ??Iname:        set           '\1'            ;Iname:= Arg1 (or $00).
*                 ifeq          ??Mname-??Iname ;If Mname=Iname set
* ??ListI:          set         (??ListI)!(2)   ;ListI.bit1, (always
*                 endc                          ;list Ifile w parent).
                  ifne          ??ListI         ;If ListI <> 0
                    restore                     ;  re-enable listing,
                    page                        ;  & start new page.
  opt mex
  !BEGIN_Ifile  \1
  restore                                       ;  Re-construct hdr.
                  endc                          ;endif
                ENDM



END_Ifile       MACRO           ifile_name      ;Four characters max.
                ??FAIL_p        <\0\2\3\4\5>    ;Arg1 only...optional.
                  ifne          ??Ibegun-1      ;Check: Any BEGIN yet?
                    fail  (499)               ! Unexpected END_Ifile.
                  endc                          ;FAIL if missing BEGIN.
  ??Ibegun:       set           0               ;Record I-file exit,
  ??Iname:        set           $00000000       ;set Iname to "none".
                  ifne          ??ListI         ;If Ifile was listed
* ??ListI:          set         (??ListI)&("2)  ; clear ListI.bit1 and
                    page                        ; setup final page-eject
                  endc                          ;endif
                  restore                       ;Re-enable listing mode.
                ENDM

  ??PAGE
* std_ops.hs .... EXTERNAL / GLOBAL
* =================================

************************************************************************
*                                                                      *
*  The macros EXTERNAL/GLOBAL should be used in place of assembly      *
*  directives XREF/XDEF to declare imported/exported identifiers.      *
*                                                                      *
*    EXTERNAL  [section_name:]symbol_name                              *
*    ------------------------------------                              *
*    This macro generates an XREF directive unless the names of the    *
*    current include file and the current module are identical;  if    *
*    the names are identical, the XREF is suppressed.  This allows     *
*    a "parent module" to INCLUDE its own header file (filename.hs)    *
*    without errors due to conflicting XREF/XDEF declarations.         *
*                                                                      *
*    GLOBAL  symbol_name                                               *
*    -------------------                                               *
*    This macro unconditionally generates an XDEF directive;  future   *
*    versions may be enhanced to provide additional services.          *
*                                                                      *
************************************************************************


EXTERNAL        MACRO           section_symbol  ;Any legal sect:symbol.
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;require section:symbol,
                ??FAIL_p        <\2\3\4\5>      ;but no other arguments.
                  ifne          ??Iname-??Mname ;Import section:symbol
                    xref        \1              ;unless IFILE "belongs"
                  endc                          ;to the current MODULE.
                ENDM



GLOBAL          MACRO           symbol_name     ;Any legal identifier.
                ??FAIL_p        <\0>            ;No qualifier allowed,
                ??FAIL_np       <\1>,<*>        ;require symbol_name,
                ??FAIL_p        <\2\3\4\5>      ;but no other args.
                  xdef          \1              ;Export symbol_name.
                ENDM


  ??PAGE
* std_ops.hs .... CHECK_Iconst
* ============================

************************************************************************
*                                                                      *
*  CHECK_Iconst  <constant_1>,<constant_2>                             *
*  ---------------------------------------                             *
*  This macro simply compares the values of two absolute (assembly-    *
*  time) constants and FAILs if they are not equal.  It is used to     *
*  verify that an absolute constant declared in an include file has    *
*  the same value as that defined by the "parent module".              *
*                                                                      *
************************************************************************


CHECK_Iconst    MACRO           const1,const2   ;Any legal identifiers.
                ??FAIL_p        <\0>            ;No qualifier allowed
                ??FAIL_np       <\1>,<*>        ;Arg1 must exist,
                ??FAIL_np       <\2>,<*>        ;Arg2 must exist,
                ??FAIL_p        <\3\4\5\6>      ;no other args.
                  ifne          (\1)-(\2)       ;Check Module vs Ifile
                  opt mex                       ;
                    fail  (499)               ! CONSTANT ERROR: \1 <> \2
                  restore                       ;
                ENDM



* End of include file std_ops.hs
  END_Ifile
